
/** \file bfemu.h
 *
 * Header file of exported Blackfin emulation functions
 *
 * (c) 11/2004 Martin Strubel <hackfin@section5.ch>
 *
 * $Id: bfemu.h 31 2005-06-08 03:02:18Z philwil $
 *
 */

/** \example main.c
 *
 * Example test program
 */

#ifndef _BFEMU_H
#define _BFEMU_H

#define BFIN_REGISTER        unsigned long
#define BFIN_REGISTER16      unsigned short
#define ADDR                 unsigned long

struct _cpu;

#define CPU struct _cpu *

////////////////////////////////////////////////////////////////////////////
// DEFINES

/** CPU state
 */

typedef enum {
	CPUSTATE_NORMAL,                  ///< Normal state (running)
	CPUSTATE_EMULATION,               ///< In emulation mode
	CPUSTATE_STEP,                    ///< In single step mode
} CpuState;

/** Tokens for Emulation Control
 * ( emulation_config() )
 */

enum {
	EMUIR_SIZE,                       ///< EMUIR register size
	EMUDAT_SIZE,                      ///< EMUDAT register size
	EMULOOP_SIZE,                     ///< Instruction loop size [1,2]
	EMU_STEP                          ///< Single step mode [on, off]
};


enum {
	WP_DISABLE,
	WP_READ,
	WP_WRITE,
	WP_ALL
};


// EMUDAT register size tokens

#define EMUDAT_SIZE_32  0             ///< EMUDAT register size = 32
#define EMUDAT_SIZE_40  (1 << 7)      ///< EMUDAT register size = 40
#define EMUDAT_SIZE_48  (2 << 7)      ///< EMUDAT register size = 48

// EMUIR register size tokens

#define EMUIR_SIZE_64   0             ///< EMUIR register size = 64
#define EMUIR_SIZE_48   (1 << 4)      ///< EMUIR register size = 48
#define EMUIR_SIZE_32   (2 << 4)      ///< EMUIR register size = 32


////////////////////////////////////////////////////////////////////////////
// CPU identification

#define IDCODE_BF533 0x027a50cb
#define IDCODE_BF537 0x027c80cb

// TODO: More BF cpus

////////////////////////////////////////////////////////////////////////////
// Register stuff

// DBGSTAT register flags
#define DBGSTAT_EMUDOF                  0x0001
#define DBGSTAT_EMUDIF                  0x0002
#define DBGSTAT_EMUDOOVF                0x0004
#define DBGSTAT_EMUDIOVF                0x0008
#define DBGSTAT_EMUREADY                0x0010
#define DBGSTAT_EMUACK                  0x0020
#define DBGSTAT_EMUCAUSE                0x03C0
#define DBGSTAT_BIST_DONE               0x0400
#define DBGSTAT_LPDEC0                  0x0800
#define DBGSTAT_IN_RESET                0x1000
#define DBGSTAT_IDLE                    0x2000
#define DBGSTAT_CORE_FAULT              0x4000
#define DBGSTAT_LPDEC1                  0x8000

#define EMULATION_CAUSE(x) ((x >> 6) & 0xf)

#define EMUCAUSE_EMUEXCPT               0x0
#define EMUCAUSE_EMUIN                  0x1
#define EMUCAUSE_WATCHPT                0x2
#define EMUCAUSE_PERFMON0               0x4
#define EMUCAUSE_PERFMON1               0x5
#define EMUCAUSE_STEP                   0x8

/** \defgroup Emulation Emulation state handling
 *
 * These functions control the emulation state of the CPU
 */

/** \defgroup Wpu Watchpoint unit/Hardware breakpoints
 *
 * These functions provide control of the Watchpoint unit.
 * Hardware assisted breakpoints (for example, breakpoints in RO
 * memory) are realized via these functions.
 * 
 */

/** \defgroup RegMem    Register and Memory access
 *
 * Register and memory space read/write
 *
 */

/** \defgroup JTAG      JTAG initialization
 *
 * Functions to initialize the JTAG chain and parts
 *
 */

/** \addtogroup Emulation
 * @{ */

/** Initialize emulation. This must be called before anything else.
 */
int           emulation_init(CPU cpu);

/**
 * Exit emulation and turn off emulator unit (save power)
 */
void          emulation_exit(CPU cpu);

/** Enter emulation state 
 */
void          emulation_enter(CPU cpu);

/** Exit emulation state; 'go'.
 */
void          emulation_leave(CPU cpu);

/** Enter single stepping mode
 */
void          emulation_enter_singlestep(CPU cpu);

/** Return from emulation (go). 
 *
 * This function does not change the CPU state (i.e. is used in
 * single step mode)
 *
 */
void          emulation_go(void);

/** Leave single step mode
 */
void          emulation_leave_singlestep(CPU cpu);

/** Flush memory changes
 *
 * This function invalidates 'n' 16 bit instructions in the processor cache at
 * the specified address. This is to make sure that there are no zombie
 * breakpoints around.
 */

void          emulation_flush(CPU cpu, ADDR addr, int n);

/** Configure emulation.
 *
 * \param mode  one of [#EMUIR_SIZE, #EMUDAT_SIZE, #EMULOOP_SIZE, #EMU_STEP]
 * \param value Depending on the mode:
 *              \li EMUIR_SIZE:    [EMUIR_SIZE_32, EMUIR_SIZE_48, EMUIR_SIZE_64]
 *              \li EMULOOP_SIZE:  [1, 2]
 *              \li EMUDAT_SIZE:   [EMUDAT_SIZE_32, EMUDAT_SIZE_40,
 *                                  EMUDAT_SIZE_48]
 *              \li EMU_STEP:      [0, 1]
 *
 */
int           emulation_config(CPU cpu, int mode, int value);

////////////////////////////////////////////////////////////////////////////
// STATUS QUERY

/** Return emulation state for state debugging
 */
CpuState      emulation_state(CPU cpu);

/* Get value of IDCODE register
 *
 * \param   code: Pointer to variable where IDCODE is stored
 *
 * \return < 0: error
 */
int get_idcode(CPU cpu, unsigned long *code);

/* Get value of DBGSTAT register
 */
BFIN_REGISTER get_dbgstat(CPU cpu);

/** @} */

////////////////////////////////////////////////////////////////////////////
// Watchpoint/Hardware breakpoints

/** \addtogroup Wpu
 * @{ */

/** Initialize CPUs watchpoint unit
 * \param enable      1: enable, 0: disable */
int wpu_init(CPU cpu, int enable);

/** Set hardware breakpoint on CPU
 *
 * \param cpu     The cpu handle
 * \param n       The number of the breakpoint [0..5]
 * \param on      1: enable, 0: disable
 */

int wpu_set_hbreak(CPU cpu, int n, ADDR addr, int enable);

int wpu_set_watch(CPU cpu, int n, ADDR addr, int mode);

/** Returns an 8 bit vector reflecting the source of the watchpoint.
 * A set bit n means, that the watchpoint event was caused by watchpoint
 * n. [0,5] : Instruction address watchpoints, [6,7]: Data address WP.
 * A call to this function clears the bit vector (WPSTAT register).
 */

int wpu_cause(CPU cpu);

/** @} */

////////////////////////////////////////////////////////////////////////////
// JTAG init/exit

/** \addtogroup JTAG
 * @{ */

/** Initialize JTAG part.
 *
 * \param argv   Pointer array to the following string sequence, equivalent
 *               to the JTAG tools 'cable' command.
 *               \li driver: [parallel, ppdev, ..]
 *               \li device: The device specification (address or device name)
 *               \li cable:  The JTAG cable type
 *
 *               If argv == 0, the default parameters are used.
 *
 * \param cpu    Pointer to a CPU handle to be returned
 *
 * \return       1: ok, error else.
 */
int           jtag_init(char * const *argv , CPU *cpu);

/** Free all resources used by the CPU handle 'cpu' 
 */
void          jtag_exit(CPU cpu);

/** @} */

////////////////////////////////////////////////////////////////////////////
// MID LEVEL

/** \addtogroup RegMem
 * @{ */

/** Read from CPU side memory
 *
 * \return 0: no error, < 0: error
 */
int           get_memory(CPU cpu, ADDR addr, unsigned long count,
		                           unsigned char *buf);

// TODO: doc
int           get_memory_word(ADDR addr, unsigned long *buf, int sizecode);

#define GET_MMR32(addr, buf) get_memory_word(addr, buf, 0)

#define GET_MMR16(addr, buf) get_memory_short(addr, buf, 1)


/** Write to CPU side memory
 *
 * \return 0: no error, < 0: error
 */
int           set_memory(CPU cpu, ADDR addr, unsigned long count,
		                           const unsigned char *buf);

/** Get CPU register value
 *
 * This function retrieves the content of a core register via JTAG.
 * This is done with a RegMv instruction, scanned through EMUIR.
 *
 * \param regno     A register token from enum bfin_registers {..}
 *                  (see bfin-registers.h)
 *
 */
BFIN_REGISTER get_cpuregister(CPU cpu, int regno);

/** Set CPU core register value
 * \param regno     A register token from enum bfin_registers {..}
 *                  (see bfin-registers.h)
 *
 * \param value     The register value
 *
 */
void          set_cpuregister(CPU cpu, int regno, BFIN_REGISTER value);

/** Reset CPU
 *  This function resets the CPU according to the mode value:
 *
 *  \param mode     1: reset Core, 2: reset System, 3: both. A value of 0
 *                  causes no action.
 */
void          cpu_reset(CPU cpu, int mode);

/** Get memory mapped register
 * of size n
 */

/** @} */


/** Return identification string and revision from CPU id
 *
 * \param rev      pointer to revision variable to filled in
 * \return  identification string
 */

char *detectDevice(CPU cpu, unsigned int *rev);

#endif
